package com.jeasonzhao.report.engine.impl;

import java.sql.SQLException;

import com.jeasonzhao.commons.logger.BasicLogger;
import com.jeasonzhao.commons.logger.Logger;
import com.jeasonzhao.commons.utils.DataTypes;
import com.jeasonzhao.report.dataset.DataCell;
import com.jeasonzhao.report.dataset.DataSet;
import com.jeasonzhao.report.dataset.PageInfo;
import com.jeasonzhao.report.dataset.RowInfo;
import com.jeasonzhao.report.engine.ConfigurationValue;
import com.jeasonzhao.report.engine.PrepareSQL;
import com.jeasonzhao.report.engine.SqlPreparation;
import com.jeasonzhao.report.engine.repo.DatabaseConfigurationRepository;
import com.jeasonzhao.report.exceptions.DataSetGenerateException;
import com.jeasonzhao.report.model.ReportColumn;
import com.jeasonzhao.report.model.ReportColumnCollection;
import com.jeasonzhao.report.model.ReportDatabaseConfiguration;
import com.jeasonzhao.report.msg.MessageCodes;
import com.jeasonzhao.report.engine.DatabasePool;
import com.jeasonzhao.commons.db.Sqlca;

@ConfigurationValue("SQL,Database,DB")
public class SqlDataSetProvider extends AbstractDataSetProvider
{
    public final static int MinimumPagesize = 10;

    public SqlDataSetProvider()
    {
    }

    public DataSet getDataSet(Logger log,int nPageSize,int nPageNo)
        throws DataSetGenerateException
    {
        //Make sure no needs to check the log.
        if(null == log)
        {
            log = BasicLogger.DUMMY;
        }
        //Adjust the pagesize and pageno.
        nPageNo = Math.max(nPageNo,0);
        nPageSize = nPageSize < MinimumPagesize ? 0 : nPageSize;
        //Initilize row indexers.
        int nRowIndex = 0;
        int nAllRowsCount = 0;
        int nSkipRowsCount = nPageSize <= MinimumPagesize ? 0 : nPageSize * nPageNo;
        Sqlca sqlcaDestination = null;
        try
        {
            log.debug(DataSetProviderMessage.format(DataSetProviderMessage.MESSAGE_PREPARE_SQL,report.getSqlStatement()));
            SqlPreparation sp = PrepareSQL.prepareSqlJavaStyle(report,report.getSqlStatement()
                ,report.getParameters());
            ReportDatabaseConfiguration dbc = DatabaseConfigurationRepository.getInstance().get(report);
            if(null == dbc)
            {
                throw new DataSetGenerateException(DataSetProviderMessage.format(DataSetProviderMessage.MESSAGE_NO_DATABASE_BY_ID,report.getDatabaseId()));
            }
            log.debug(DataSetProviderMessage.format(DataSetProviderMessage.MESSAGE_CONNECTING,MessageCodes.getDescription(dbc)));
            sqlcaDestination = DatabasePool.getInstance().getSqlca(dbc.getDatabaseId());
            DataSet dataset = new DataSet();
            dataset.setReportColumns(ReportColumnCollection.from(report.getColumns()));
            sqlcaDestination.setSql(sp.getSql());
            for(int n = 0;null != sp.getParameters() && n < sp.getParameters().size();n++)
            {
                com.jeasonzhao.commons.db.SqlParameter p = sp.getParameters().get(n);
                sqlcaDestination.set("" + n + 1,p.getSqlType(),p.getValue());
            }
            sqlcaDestination.execute();
            log.debug(DataSetProviderMessage.get(DataSetProviderMessage.MESSAGE_EXECUTING));
            while(sqlcaDestination.next())
            {
                RowInfo row = queryRow(sqlcaDestination,dataset,nRowIndex);
                if(nAllRowsCount < nSkipRowsCount ||
                   nPageSize > 0 && (nRowIndex + 1) > nPageSize)
                {
                    nAllRowsCount++;
                    continue;
                }
                nAllRowsCount++;
                dataset.addRow(row);
                nRowIndex++;
            }
            dataset.setPageInfo(new PageInfo(nPageNo,nPageSize,nAllRowsCount,nSkipRowsCount));
            return dataset;
        }
        catch(SQLException excep)
        {
            throw new DataSetGenerateException(excep.getMessage(),excep);
        }
        catch(Exception excep)
        {
            throw new DataSetGenerateException(excep.getMessage(),excep);
        }
        finally
        {
            if(null != sqlcaDestination)
            {
                sqlcaDestination.closeAll();
            }
        }

    }

    private RowInfo queryRow(Sqlca sqlca,DataSet table,int nRowIndex)
        throws Exception
    {
        RowInfo row = new RowInfo();
        for(int nColumn = 0;nColumn < table.getHeaderColumns().size();nColumn++)
        {
            ReportColumn col = table.getHeaderColumn(nColumn);
            DataCell cell = new DataCell();
            cell.setColIndex(nColumn);
            cell.setRowIndex(nRowIndex);
            cell.setDataType(col.getDataType());
            cell.setVisiable(!col.isHidden());
            Object value = null;
            if(col.getColumnType().isCalcColumn() == false
               && col.getFieldName() != null
               && col.getFieldName().trim().length() > 0)
            {
                if(DataTypes.BOOL.getId() == col.getDataType().getId())
                {
                    value = Boolean.valueOf(sqlca.getInt(col.getFieldName()) > 0);
                }
                else if(DataTypes.DATE.getId() == col.getDataType().getId())
                {
                    value = sqlca.getDate(col.getFieldName());
                }
                else if(DataTypes.DOUBLE.getId() == col.getDataType().getId())
                {
                    value = new Double(sqlca.getDouble(col.getFieldName()));
                }
                else if(DataTypes.INT.getId() == col.getDataType().getId())
                {
                    value = sqlca.getInteger(col.getFieldName());
                }
                else
                {
                    value = sqlca.getString(col.getFieldName());
                }
            }
            else
            {
                value = null;
            }
            cell.setValue(value);
            cell.setReportColumn(col);
            row.addElement(cell);
        }
        return row;
    }
}
